/// 字符串常用的方法
pub fn start() {
    let mut v = String::from("boros");
    let mut_val = v.get_mut(1..2).unwrap();
    println!("{:?}", mut_val);
    let x = mut_val.as_mut_ptr();
    unsafe {
        *x = 97;
    }
    println!("{}", v);

    // 可以通过is_char_boundary 方法来验证某个索引位置是否为合法的 字符边界
    // 在使用字符串内建的get_mut,get, split_at和 split_at_mut等方法分割字符串时 ，
    // 需要注意，一定要使用合法的字符串边界索引，否则就会引起线程崩溃
    let s = "Per Martin-LÕf";
    println!("{}", s.is_char_boundary(12));
    println!("{}", s.is_char_boundary(13)); // false Õ占用2个字码，所以不是字符边界

    // 删除字符串
    let mut s = String::from("hěllo");
    s.remove(3);
    println!("{}", s); // hělo
    assert_eq!(Some('o'), s.pop());
    println!("{}", s); // hěl
    assert_eq!(Some('l'), s.pop());
    assert_eq!(Some('ě'), s.pop());

    s = String::from("hěllo");
    s.truncate(3);
    println!("{}", s); // hě
    s.clear();

    s = String::from("α is alpha, β is beta");
    let beta_offset = s.find('β').unwrap_or(s.len());
    println!("{}", beta_offset); // 13
    let t = s.drain(..beta_offset).collect::<String>();
    println!("{}", t); // 输出"α is alpha, "
    println!("{}", s); // β is beta

    s.drain(..);
    println!("{}", s);

    // 字符串的查找
    // 提供了另外的字符串匹配功能供开发者使用， 一共包含 20 个方法。 这20个方法涵盖了以下几种字符串匹配操作:
    // ·存在性判断。 相关方法包括contains、 starts_with、 ends_with
    // .位置匹配 。相关方法包括 find、 rfind。
    // ·分割字符串 。相关方法包括 split、rsplit、split_terminator、rsplit_terminator、splitn、rsplitn。
    // .捕获匹配。 相关方法包括 matches、 rmatches、 match_indices、 rmatch_indices。
    // ·删除匹配。 相关方法包括 trim_matches, trim_left_matches、trim_right_matches。
    // ·替代匹配。 相关方法包括 replace、 replacen

    // 存在性判断
    let bananas = "bananas";
    assert!(bananas.contains('a'));
    assert!(bananas.contains("an"));
    assert!(bananas.contains(char::is_lowercase));
    assert!(bananas.starts_with('b'));
    assert!(!bananas.ends_with("nana"));
    // 注意 ，在代码中，contains 的参数是三种不同的类型，分别为 char、&str 和自1 pointer，
    // 这是因为 contains 是一个泛型方法
    // contains的参数 pat是一个泛型，并且有一个 Pattern<'a>限 定。
    // Pattern<’a>是一个专门用于搜索&『astr字符串的模式 trait。 Rust中的 char类型、 String、
    // &str、&&str、&[char]类型， 以及 FnMut(char) -> bool的闭包均己实现了该 trait。因此，
    // contains 才可 以接收不同类型的值作为参数。
    // pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
    //    pat.is_contained_in(self)
    // }

    // 位置匹配
    let s = "Löwe 老虎 Léopard";
    assert_eq!(s.find('w'), Some(3));
    assert_eq!(s.find('老'), Some(6));
    // 使用的 rfind 方法，表示从右向左来匹配字符串， r 前缀代表右边 (right)，所以它返回的结果是 Some(l3)
    // 从后面找到'L'的index
    assert_eq!(s.rfind('L'), Some(13));
    assert_eq!(s.find(char::is_whitespace), Some(5));
    assert_eq!(s.find(char::is_lowercase), Some(1));

    // 分割字符串
    let s = "Löwe 虎 Léopard";

    // split方法同样支持Pattern参数，本次该方法使用闭包作为参数。
    // 闭包的行为是想通过字符串中字符的码位范围来锁定中文字符 ，然后以中文字符作为字符串的分割位置
    let v = s
        .split(|c| (c as u32) >= (0x4E00 as u32) && (c as u32) <= (0x9EA5 as u32))
        .collect::<String>();
    println!("{}", v);

    let v = s
        .split(|c| (c as u32) >= (0x4E00 as u32) && (c as u32) <= (0x9EA5 as u32))
        .collect::<Vec<_>>();
    println!("{:?}", v); // ["Löwe ", " Léopard"]

    let v = "abc1defXghi"
        .split(|c| c == '1' || c == 'X')
        .collect::<Vec<_>>();
    println!("{:?}", v); // ["abc", "def", "ghi"]

    // 使用了 splitn 方法，注意这个方法的命名 比 split 多了一个 n， 这个 n 代表指定分割的数组的长度。
    // 该方法的第一个参数就是指定要分割的数组长度，第二个参数为 要分割的 pattern参数
    let v = "Mary had a little lambda"
        .splitn(3, ' ')
        .collect::<Vec<_>>();
    println!("{:?}", v); // ["Mary", "had", "a little lambda"]

    let v = "A.B.".split('.').collect::<Vec<_>>();
    println!("{:?}", v); // ["A", "B", ""]

    // split_terminator 会把分割结果数组最后一位出现的空字符串去掉。
    let v = "A.B.".split_terminator('.').collect::<Vec<_>>();
    println!("{:?}", v); // ["A", "B"]

    let v = "A..B..".split(".").collect::<Vec<_>>();
    println!("{:?}", v); // ["A", "", "B", "", ""]

    // 去掉了最后一个
    let v = "A..B..".split_terminator(".").collect::<Vec<_>>();
    println!("{:?}", v); // ["A", "", "B", ""]

    let v = "A..B..".rsplit_terminator(".").collect::<Vec<_>>();
    println!("{:?}", v); // ["", "B", "", "A"]

    // 捕获匹配
    let v = "abcXXXabcYYYabc".matches("abc").collect::<Vec<_>>();
    println!("{:?}", v); // ["abc", "abc", "abc"]

    let v = "1abc2abc3".rmatches(char::is_numeric).collect::<Vec<_>>();
    println!("{:?}", v); // ["3", "2", "1"]

    // match_indices方法，返回的结果是元组数组，其中元组的第一个元素代表匹配字符的位置索引，
    // 第二个元素为匹配的字符本身
    let v = "abcXXXabcYYYabc".match_indices("abc").collect::<Vec<_>>();
    println!("{:?}", v); // [(0, "abc"), (6, "abc"), (12, "abc")]

    let v = "1abc2abc3"
        .rmatch_indices(char::is_numeric)
        .collect::<Vec<_>>();
    println!("{:?}", v); // [(8, "3"), (4, "2"), (0, "1")]

    // 删除匹配
    let s = " hello\tworld\t";
    assert_eq!("hello\tworld", s.trim());
    assert_eq!("hello\tworld\t", s.trim_start());
    assert_eq!(" hello\tworld", s.trim_end());

    // 没有去掉中间的数字
    let v = "12foo1bar12".trim_matches(char::is_numeric);
    println!("{:?}", v); // "foo1bar"

    // 替代匹配
    let s = "hello\tworld\t";
    assert_eq!("hello world ", s.replace("\t", " "));
    assert_eq!("hello world", s.replace("\t", " ").trim());
    let s = "this is old old 123";
    assert_eq!("this is new new 123", s.replace("old", "new"));
    assert_eq!("this is new old 123", s.replacen("old", "new", 1));
    assert_eq!("this is ald ald 123", s.replacen("o", "a", 3));
    assert_eq!(
        "this is old old new23",
        s.replacen(char::is_numeric, "new", 1)
    );
}
